/////precompiled////////
#include "precompiled.h"
////////////////////////


#include "svl_TVariant.h"
using namespace svl;
                      
// TVariant ////////////////////////////////////////////////////////////////////
//svl_CppMap(TVariant);

//
TVariant &TVariant::operator = (const TVariant &V_)
{
  TVariant &V = (TVariant&)V_; switch (V.type)
  {
    case EType_Null:      this->SetNull(); break;
    case EType_Bool:     *this = (bool)V; break;
    case EType_Integer:  *this = (int)V; break;
    case EType_Double:   *this = (double)V; break;
    case EType_String:   *this = (TString)V; break;
    case EType_Mem:      *this = (TMem&)V; break;
    case EType_Object:   *this = (TObject&)V; break;
    case EType_Pointer:  *this = (TPointer*)V; break;
    case EType_DateTime: *this = (TDateTime)V; break;

    default: Except("operator = (const TVariant &V)");
  }
  return *this;
}
            
//
TVariant &TVariant::operator = (int V)
{
  Delete(); type = EType_Integer; value.Integer = V; return *this;
}

//
TVariant &TVariant::operator = (bool V)
{
  Delete(); type = EType_Bool; value.Bool = V; return *this;
}

//
TVariant &TVariant::operator = (double V)
{
  Delete(); type = EType_Double; value.Double = V; return *this;
}

//
TVariant &TVariant::operator = (TString V)
{
  Delete(); type = EType_String; value.PString = new TString(V); return *this;
}

//
TVariant &TVariant::operator = (const TMem &V)
{
  Delete(); type = EType_Mem;
  value.PMem = new TMem((TMem&)V); return *this;
}

//
TVariant &TVariant::operator = (const TObject &V_)
{
  Delete(); type = EType_Object; TObject &V = (TObject&)V_;
  value.PObject = V.New();
  value.PObject->CopyFrom(&V);
  return *this;
}

//
TVariant &TVariant::operator = (TPointer *V)
{
  Delete(); type = EType_Pointer;
  value.Pointer = V;
  return *this;
}

//
TVariant &TVariant::operator = (char *V)
{
  Delete(); type = EType_String; value.PString = new TString(V); return *this;
}

//
TVariant &TVariant::operator = (TDateTime V)
{
  Delete(); type = EType_DateTime;
  value.PDateTime = new TDateTime(V); return *this;
}

//
TVariant::operator bool()
{
  switch (type)
  {
    case EType_Bool:
      return value.Bool;

    case EType_Integer:
      return value.Integer == 0 ? true : false;

    case EType_Double:
      return value.Double == 0 ? true : false;

    //case EType_String:
    //  if (value.PString) { return value.PString->ConvertToBool();}
    //  return 0;
  }
  Except("operator bool()"); return 0;
}

//
TVariant::operator int()
{
  switch (type)
  {
    case EType_Integer:
      return value.Integer;

    case EType_Double:
      return static_cast<int>(value.Double);

    case EType_String:
      if (value.PString) { return value.PString->ConvertToDWORD();}
      return 0;
  }
  Except("operator int()"); return 0;
}

//
TVariant::operator double()
{
  switch (type)
  {
    case EType_Integer:
      return value.Integer;

    case EType_Double:
      return value.Double;
                                    
    case EType_String:
      if (value.PString) { return value.PString->ConvertToDouble();}
      return 0;
  }
  Except("operator double()"); return 0;
}

//
TVariant::operator TString()
{
  TString V; switch (type)
  {
    case EType_Bool:
      V << value.Bool; return V;

    case EType_Integer:
      V << value.Integer; return V;

    case EType_Double:
      V << value.Double; return V;

    case EType_String:
      if (value.PString) { return *value.PString;}
      return V;

    case EType_DateTime:
      if (value.PDateTime) { V << value.PDateTime->DateTimeString();}
      return V;
  }
  Except("operator TString()"); return V;
}

//
TVariant::operator TMem&()
{
  static TMem V; switch (type)
  {
    case EType_Mem:
      if (value.PMem) { return *value.PMem;}
      return V;
  }
  Except("operator TMem()"); return V;
}

//
TVariant::operator TObject&()
{
  static TObject *V = NULL; switch (type)
  {
    case EType_Object:
      if (value.PObject) { return *value.PObject;}
      //return V;
  }
  Except("operator TObject()"); return *V;
}

//
TVariant::operator TPointer*()
{
  switch (type)
  {
    case EType_Pointer:
      return value.Pointer;
  }
  Except("operator TPointer*()"); return NULL;
}

//
TVariant::operator TDateTime()
{
  static TDateTime V; switch (type)
  {
    case EType_String:
      if (value.PString) { return TDateTime(value.PString->S());}
      return V;

    case EType_DateTime:
      if (value.PDateTime) { return *value.PDateTime;}
      return V;
  }
  Except("operator System::TDateTime()"); return V;
}

//
void TVariant::Delete()
{
  switch (type)
  {
    case EType_Null:     break;
    case EType_Bool:     break;
    case EType_Integer:  break;
    case EType_Double:   break;
    case EType_String:   delete value.PString; break;
    case EType_Mem:      delete value.PMem; break;
    case EType_Object:   delete value.PObject; break;
    case EType_Pointer:  break;
    case EType_DateTime: delete value.PDateTime; break;

    default: Except("Delete");
  }
  ::memset(&value,0,sizeof(value));
}

//
TString TVariant::GetInfo()
{
  switch (type)
  {
    case EType_Null:   return "NULL";
    case EType_String: return TString() << "\"" << String() << "\"";
    //
    case EType_Bool:
      return value.Bool ? "true" : "false";

    case EType_Integer:
    case EType_Double:
    case EType_DateTime: return String();
    //
    case EType_Mem: return TString("Mem");
    //
    case EType_Object:  return TString("Object");
    case EType_Pointer: return Pointer();//TString("Pointer");

    default: Except("GetInfo");
  }
  return TString();
}

//
TInfoParam TVariant::AddInfoTo(TInfoParam Info) 
{ 
  return Info.Add(Info.GetAttrName(),GetInfo(),Info.GetNGroup());
}

// TVariantArray ///////////////////////////////////////////////////////////////
//svl_CppMap(TVariantArray);

//
TObject *TVariantArray::New()
{
  return new TVariantArray;
}

//
void TVariantArray::CopyFrom(TObject *P)
{
  TVariantArray *From = (TVariantArray*)P;

  Clear(); 
  for (int N = 0; N < From->Count(); N++) {
    if (From->GetEnDelete(N)) {
      Add(new TVariant(From->Get(N)),true);
    }
    else { 
      Link(From->Get(N));
    }
  }
}

// TVariantStack ///////////////////////////////////////////////////////////////

//
void TVariantStack::Link(TVariant &V)
{
  if (!list.IsEmpty()) {
    Except("Link");
  }
  varArray.Add(&V,false);
}

//
void TVariantStack::Push()
{
  if (varArray.Count()) {
    TObject *P = new TObject(varArray);

    NewVarA1FromA2 (P->CopyVarArray,P->LinkVarArray);
    CopyVarA1FromA2(P->CopyVarArray,P->LinkVarArray);

    list.InsertTop(P,true);
  }
}

//
bool TVariantStack::Pop()
{
  TObject *P = (TObject*)list.GetTop(); 
  
  if (P) {
    CopyVarA1FromA2(P->LinkVarArray,P->CopyVarArray);
  }
  return list.DeleteTop();
}

//
void TVariantStack::NewVarA1FromA2(TVariantArray &A1,TVariantArray &A2)
{
  A1.Clear(); 
  for (int N = 0; N < A2.Count(); N++) {
    A1.Add(new TVariant,true);
  }
}

//
void TVariantStack::CopyVarA1FromA2(TVariantArray &A1,TVariantArray &A2)
{
  if (A1.Count() != A2.Count()) {
    Except("CopyVarA1FromA2");
  }
  for (int N = 0; N < A2.Count(); N++) {
    A1[N] = A2[N];
  }
}
